﻿#include "CustomFormControl.ListViewNF.h"

namespace CustomFormControl
{

    ListViewNF::ListViewColumnSorter::ListViewColumnSorter() : _objectCompare(new CaseInsensitiveComparer())
    {
        // Initialize the column to '0'
        _columnToSort = 0;

        // Initialize the sort order to 'none'
        _orderOfSort = SortOrder::None;

        // Initialize the CaseInsensitiveComparer object
    }

    int ListViewNF::ListViewColumnSorter::Compare(std::any x, std::any y)
    {
        // Cast the objects to be compared to ListViewItem objects
        ListViewItem *listviewX = std::any_cast<ListViewItem*>(x);
        ListViewItem *listviewY = std::any_cast<ListViewItem*>(y);

        // Compare the two items
        int compareResult = _objectCompare->Compare(listviewX->SubItems[_columnToSort]->Text, listviewY->SubItems[_columnToSort]->Text);

        // Calculate correct return value based on object comparison
        if (_orderOfSort == SortOrder::Ascending)
        {
            // Ascending sort is selected, return normal result of compare operation
            return compareResult;
        }
        if (_orderOfSort == SortOrder::Descending)
        {
            // Descending sort is selected, return negative result of compare operation
            return (-compareResult);
        }
        // Return '0' to indicate they are equal
        return 0;
    }

    void ListViewNF::ListViewColumnSorter::setSortColumn(int value)
    {
        _columnToSort = value;
    }

    int ListViewNF::ListViewColumnSorter::getSortColumn() const
    {
        return _columnToSort;
    }

    void ListViewNF::ListViewColumnSorter::setOrder(SortOrder *value)
    {
        _orderOfSort = value;
    }

    SortOrder *ListViewNF::ListViewColumnSorter::getOrder() const
    {
        return _orderOfSort;
    }

    ListViewNF::ListViewNF() : _sorter(new ListViewColumnSorter())
    {
        _itemSelectionChangedTimer->Interval = 1;
        _selectedIndexChangedTimer->Interval = 1;

        _itemSelectionChangedTimer->Tick += [&] (sender, e)
        {
            OnItemSelectionChanged(_itemSelectionChangedEventArgs);
            _itemSelectionChangedEventArgs = nullptr;
        };
        _selectedIndexChangedTimer->Tick += [&] (sender, e)
        {
            OnSelectedIndexChanged(_selectedIndexChangedEventArgs);
            _selectedIndexChangedEventArgs = nullptr;
        };

        //Activate double buffering
        SetStyle(ControlStyles::OptimizedDoubleBuffer | ControlStyles::AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        SetStyle(ControlStyles::EnableNotifyMessage, true);

        ListViewItemSorter = _sorter;
        ColumnClick += ListViewNF_ColumnClick;
    }

    void ListViewNF::ListViewNF_ColumnClick(std::any sender, ColumnClickEventArgs *e)
    {
        if (e->Column == _sorter->getSortColumn())
        {
            _sorter->setOrder(_sorter->getOrder() == SortOrder::Ascending ? SortOrder::Descending : SortOrder::Ascending);
        }
        else
        {
            _sorter->setSortColumn(e->Column);
            _sorter->setOrder(SortOrder::Ascending);
        }
        Sort();
    }

    void ListViewNF::OnNotifyMessage(Message *m)
    {
        //Filter out the WM_ERASEBKGND message
        if (m->Msg != 0x14)
        {
            ListView::OnNotifyMessage(m);
        }
    }

    void ListViewNF::OnItemSelectionChanged(ListViewItemSelectionChangedEventArgs *e)
    {
        if (_itemSelectionChangedTimer->Enabled)
        {
            _itemSelectionChangedTimer->Stop();
            ListView::OnItemSelectionChanged(e);
        }
        else
        {
            _itemSelectionChangedEventArgs = e;
            _itemSelectionChangedTimer->Start();
        }
    }

    void ListViewNF::OnSelectedIndexChanged(EventArgs *e)
    {
        if (_selectedIndexChangedTimer->Enabled)
        {
            _selectedIndexChangedTimer->Stop();
            ListView::OnSelectedIndexChanged(e);
        }
        else
        {
            _selectedIndexChangedEventArgs = e;
            _selectedIndexChangedTimer->Start();
        }
    }
}
